package com.lvmama.pet.sync.service;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;

import com.lvmama.comm.bee.service.sync.SyncJarResourceService;
import com.lvmama.comm.sync.po.SyncJarResource;
import com.lvmama.comm.sync.utils.Constant;
import com.lvmama.pet.sync.dao.SyncJarResourceMapper;
import com.lvmama.pet.sync.service.util.SyncContextFactory;

/**
 * @author pengfei
 *
 */
public class SyncJarResourceServiceImpl implements SyncJarResourceService, ApplicationListener<ContextRefreshedEvent>{
	
	private static final Log logger = LogFactory.getLog(SyncJarResourceServiceImpl.class);
	
	private static final int RESOURCE_EXECUTOR_THREAD_NUM = 100;
	
	private static final ExecutorService exec=Executors.newCachedThreadPool();

	
	@Autowired
	private SyncJarResourceMapper jarResourceMapper;
	

	@Override
	public void save(SyncJarResource syncJarResource) throws Exception {
		
		jarResourceMapper.save(syncJarResource);
		List<SyncJarResource> list = new ArrayList<SyncJarResource>();
		list.add(syncJarResource);
		loadJar(list);
	}

	@Override
	public List<SyncJarResource> findAll() {
		return jarResourceMapper.findAll();
	}

	public void loadJar(List<SyncJarResource> list){
		for (SyncJarResource syncJarResource : list) {
			    try {
			    	String  dirPath = Constant.getInstance().getSyncJarPath();
			    	//将上传的jar写入服务器目录
					File fileDir = new File(Constant.getInstance().getSyncJarPath());
					
					if(!fileDir.exists()){
						fileDir.mkdirs();
					}
					String jarPath = fileDir+File.separator+syncJarResource.getJarName();
					
					List<URL> urls = new ArrayList<URL>();

					String[] fileNames = fileDir.list();
					
					//首次全部加载
					if(SyncContextFactory.configs.size()==0){
						load(urls,dirPath,syncJarResource);
					}else{
						for(int i=0;i<fileNames.length;i++){
							//如果服务器暂未加载jar 则重新load 或者jar 更新过重新load
							if(!fileNames[i].equals(syncJarResource.getJarName())){
                                 if(fileNames[i].indexOf(syncJarResource.getJarOriginalName().replace(".jar", ""))>-1){
                                	 new File(dirPath+File.separator+fileNames[i]).delete();
                                 }
								 load(urls,dirPath,syncJarResource);
							}
						}
					}

				} catch (Exception e) {
					e.printStackTrace();
					logger.error(syncJarResource.getJarName()+" load failed");
					continue;
				}
		        

		}
	}
	
	
	public void load(List<URL> urls,String dirPath,SyncJarResource syncJarResource) throws IOException{
		//jar 下载到当前服务器目录
		getFile(syncJarResource.getJarFile(), dirPath, syncJarResource.getJarName());
		File file = new File(dirPath+File.separator+syncJarResource.getJarName());
		urls.add(file.toURI().toURL());
		URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader();
		Class<? extends URLClassLoader> sysclass = URLClassLoader.class;
		try {
		    Method method = sysclass.getDeclaredMethod("addURL", URL.class);
		    method.setAccessible(true);
		    for (URL url : urls) {
		        method.invoke(sysloader, url);
		    }
		} catch (Throwable t) {
		    throw new IOException("Error, could not add URL to system classloader", t);
		}
		
		//加载consumer
		if(!SyncContextFactory.configs.contains(syncJarResource.getJarConsumerFileName())){
			SyncContextFactory.configs.add(syncJarResource.getJarConsumerFileName());
			SyncContextFactory.refreshContext();

		}
	}
	
	private class SyncScanJarRunner implements Runnable{

		@Override
		public void run() {
			while(true){

				try {
						List<SyncJarResource> jarResources = findAll();
						if(null!=jarResources&&jarResources.size()>0){
							loadJar(jarResources);
						}
						Thread.sleep(6000);
					
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			
			
		}
		
	}
	@Override
	public void onApplicationEvent(ContextRefreshedEvent event) {
		if(event.getApplicationContext().getDisplayName().equals("Root WebApplicationContext"))//root application context 没有parent，他就是老大.
        {  
            //需要执行的逻辑代码，当spring容器初始化完成后就会执行该方法。  
		    exec.submit(new SyncScanJarRunner());
		    //exec.shutdown();

        }		
	}
	
	/** 
     * 根据byte数组，生成文件 
     */  
    public static void getFile(byte[] bfile, String filePath,String fileName) {  
        BufferedOutputStream bos = null;  
        FileOutputStream fos = null;  
        File file = null;  
        try {  
            File dir = new File(filePath);  
            if(!dir.exists()&&dir.isDirectory()){//判断文件目录是否存在  
                dir.mkdirs();  
            }  
            file = new File(filePath+File.separator+fileName);  
            if(!file.exists()){
            	file.createNewFile();
            }
            fos = new FileOutputStream(file);  
            bos = new BufferedOutputStream(fos);  
            bos.write(bfile);  
        } catch (Exception e) {  
            e.printStackTrace();  
        } finally {  
            if (bos != null) {  
                try {  
                    bos.close();  
                } catch (IOException e1) {  
                    e1.printStackTrace();  
                }  
            }  
            if (fos != null) {  
                try {  
                    fos.close();  
                } catch (IOException e1) {  
                    e1.printStackTrace();  
                }  
            }  
        }  
    }
    

	@Override
	public SyncJarResource findByJarOriginalName(String jarOriginalName) {
		return jarResourceMapper.findByJarOriginalName(jarOriginalName);
	}

	@Override
	public void update(SyncJarResource syncJarResource) {

		jarResourceMapper.update(syncJarResource);
		List<SyncJarResource> list = new ArrayList<SyncJarResource>();
		list.add(syncJarResource);
		loadJar(list);
	}
	
	 public static void main(String[] args) {
	    	try {
				File file = new File("D:\\syncJar\\security-interface-1.0.0-SNAPSHOT-1477568563563.jar");
				file.delete();
	    		//File file = new File("D:\\security-interface-1.0.0-SNAPSHOT.jar");
				//if(!file.exists()){
					//file.createNewFile();
				//}
				//FileOutputStream fileOutputStream = new FileOutputStream(file);

				//FileOutputStream fos = new FileOutputStream(file);
				System.out.println(Constant.getInstance().getSyncJarPath());
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
}
